import cv2
import numpy as np

if __name__ == "__main__":
    # 1. 读取图像并转为灰度图
    img = cv2.imread("lena.jpg")
    # 检查图像是否读取成功
    if img is None:
        print("无法读取图像，请检查文件路径是否正确！")
    else:
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  # 转为灰度图

        # 2. 统计每个灰度值（0-255）的像素数量
        hist = [0] * 256  # 初始化灰度直方图（0-255共256个灰度）
        height, width = gray.shape  # 获取图像尺寸（高和宽）
        total_pixels = height * width  # 计算总像素数

        # 遍历每个像素，统计灰度值出现的次数
        for i in range(height):
            for j in range(width):
                gray_value = gray[i, j]  # 获取当前像素的灰度值
                hist[gray_value] += 1  # 对应灰度值的计数+1

        # 3. 计算最优阈值（OTSU算法核心）
        max_variance = 0  # 最大类间方差
        best_threshold = 0  # 最优阈值

        # 尝试所有可能的阈值（0-255）
        for threshold in range(256):
            # 计算前景（≤阈值）和背景（>阈值）的像素数
            foreground = sum(hist[:threshold + 1])  # 前景像素总数
            background = total_pixels - foreground  # 背景像素总数

            # 跳过极端情况（某一类没有像素）
            if foreground == 0 or background == 0:
                continue

            # 计算前景平均灰度
            foreground_sum = 0
            for g in range(threshold + 1):
                foreground_sum += g * hist[g]  # 灰度值×像素数之和
            foreground_avg = foreground_sum / foreground  # 平均值

            # 计算背景平均灰度
            background_sum = 0
            for g in range(threshold + 1, 256):
                background_sum += g * hist[g]  # 灰度值×像素数之和
            background_avg = background_sum / background  # 平均值

            # 计算类间方差（判断阈值好坏的指标）
            foreground_ratio = foreground / total_pixels  # 前景占比
            background_ratio = background / total_pixels  # 背景占比
            variance = foreground_ratio * background_ratio * (foreground_avg - background_avg) **2  # 类间方差

            # 更新最大方差和最优阈值
            if variance > max_variance:
                max_variance = variance
                best_threshold = threshold

        # 4. 输出结果并验证
        print(f"手动计算的最优阈值：{best_threshold}")

        # 用OpenCV内置OTSU验证
        cv_threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_OTSU)[0]
        print(f"OpenCV计算的最优阈值：{cv_threshold}")

        # 5. 用最优阈值进行二值化并显示
        _, binary_img = cv2.threshold(gray, best_threshold, 255, cv2.THRESH_BINARY)
        cv2.imshow("OTSU", binary_img)
        cv2.waitKey(0)

        cv2.imwrite('OTSU.jpg', binary_img)